package ai.people.netmon.framework.utils;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * 获取线程池时因充分考虑任务来设置最大线程数，这里只是给出一个建议值而生成的工具类
 *
 * @author Swayingleaves
 * @date 2019/4/24 12:30
 */
public class ThreadPoolUtil {
    /**
     * 获取io密集型最佳线程数
     */
    public static int getIoTypeCores() {
        final int cores = Runtime.getRuntime().availableProcessors();
        return 2 * cores;
    }

    /**
     * 获取计算密集型最佳线程数
     */
    public static int getComputationalTypeCores() {
        final int cores = Runtime.getRuntime().availableProcessors();
        return cores + 1;
    }

    /**
     * 获取io密集型最佳线程池
     */
    public static ExecutorService getIoTypePool(String poolName) {
        int cores = getIoTypeCores();
        return getThreadPool(poolName, cores, cores);
    }

    /**
     * 获取计算密集型最佳池
     */
    public static ExecutorService getComputationalTypePool(String poolName) {
        int cores = getComputationalTypeCores();
        return getThreadPool(poolName, cores, cores);
    }

    /**
     * 获取单线程
     *
     * @param poolName
     * @return
     */
    public static ExecutorService getSingleThread(String poolName) {
        return getThreadPool(poolName, 1, 1);
    }

    /**
     * https://www.jianshu.com/p/0e228dc30793
     * <p>
     * 构建线程池
     *
     * @param poolName        线程名
     * @param corePoolSize    线程池维护线程的最少数量
     * @param maximumPoolSize 线程池维护线程的最大数量
     * @return
     */
    public static ExecutorService getThreadPool(String poolName, int corePoolSize, int maximumPoolSize) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(poolName + "-pool-%d").build();
        ExecutorService pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new RejectedExecutionHandler() {
            //重写拒绝方法，采用blockingQueue的put方法，放入队列满了则等待，默认拒绝方法为满了则直接拒绝抛异常
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                try {
                    if (!executor.isShutdown()) {
                        executor.getQueue().put(r);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        return pool;
    }
}
